from rest_framework import serializers
from api import models
from rest_framework import exceptions
from utils.encrypt import create_uid, md5
from django.db import transaction
from django.db.models import Sum
import time
import random
import requests
from xml.etree import ElementTree as ET
from django.forms import model_to_dict


class PayDepositModelSerializer(serializers.ModelSerializer):
    auction_id = serializers.IntegerField(label='拍卖ID')
    item_id = serializers.IntegerField(label='拍品ID')

    class Meta:
        model = models.DepositRecord
        # fields = "__all__"
        exclude = ['auction', 'balance', 'uid', 'user']

    def validate_auction_id(self, value):
        # 检查是否已支付全场保证金
        user_object = self.context['request'].user
        exists = models.DepositRecord.objects.filter(user=user_object, auction_id=value, item__isnull=True,
                                                     status=2).exists()
        if exists:
            raise exceptions.ValidationError(detail="已支付过全场保证金")
        return value

    def validate_item_id(self, value):
        """ 检查是否已支付单品保证金 """
        user_object = self.context['request'].user
        exists = models.DepositRecord.objects.filter(user=user_object, item__id=value, status=1).exists()
        if exists:
            raise exceptions.ValidationError(detail='已支付此单品保证金')
        return value

    def validate_deposit_type(self, attrs):
        if attrs == 1:
            return attrs
        # 全场保证金,已支付过其他单品保证金，则不能再支付全场保证金。
        if attrs == 2:
            user_object = self.context['request'].user
            auction_id = self.initial_data.get('auction_id')
            exists = models.DepositRecord.objects.filter(user=user_object, auction_id=auction_id, status=2).exists()

            if exists:
                raise exceptions.ValidationError(detail='已支付其他单品保证金，无法再支付全场保证金')
            return attrs
        return exceptions.ValidationError(detail="保证金类型错误")

    def validate_amount(self, value):
        """保证金金额"""
        deposit_type = self.initial_data.get('deposit_type')

        # 单品保证金
        if deposit_type == 1:
            item_id = self.initial_data.get('item_id')
            exists = models.AuctionItem.objects.filter(id=item_id, deposit=value).exists()
            if not exists:
                raise exceptions.ValidationError(detail='保证金金额错误')
            return value

        # 全场保证金
        if deposit_type == 2:
            auction_id = self.initial_data.get('auction_id')
            exists = models.Auction.objects.filter(id=auction_id, deposit=value).exists()
            if not exists:
                raise exceptions.ValidationError(detail='保证金金额错误')
            return value

    def validate_pay_type(self, value):
        """支付保证金"""
        # 微信支付
        if value == 1:
            return value

        # 余额支付，余额是否充足。
        if value == 2:
            user_object = self.context['request'].user
            amount = self.initial_data.get('amount')
            if user_object.balance < amount:
                raise exceptions.ValidationError(detail='余额不足')
            return value

        raise exceptions.ValidationError(detail='支付方式错误')

    def create(self, validated_data):
        user_object = self.context['request'].user
        uid = create_uid(user_object.nickname)
        item_id = validated_data.pop('item_id')
        pay_type = validated_data.get('pay_type')
        amount = validated_data.get('amount')
        deposit_type = validated_data.get('deposit_type')
        # 余额支付
        if pay_type == 2:
            # 事务
            with transaction.atomic():
                user_object.balance -= amount
                user_object.save()
                deposit_object = models.DepositRecord.objects.create(**validated_data, status=2, uid=uid,
                                                                     user=user_object,
                                                                     item_id=item_id if deposit_type == 1 else None,
                                                                     balance=amount)
        # 微信支付
        if pay_type == 1:
            # 创建时，状态应该是1，在回调再次确认时，状态应为2.
            deposit_object = models.DepositRecord.objects.create(**validated_data, status=2, uid=uid, user=user_object,
                                                                 item_id=item_id if deposit_type == 1 else None,
                                                                 balance=amount
                                                                 )
            """需要微信小程序申请支付功能"""
            # ########### 2.1 创建预支付交易单 ###########
            #   https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7
            #   https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_4&index=3

            # 商户支付的key，去自己的商户平台获取
            # pay_key = "2SzCvaKgYExuItWBfYAqJFs72uUleD14"
            #
            # data = {
            #     'appid': 'wx55cca0b94f723dc7',
            #     'mch_id': '1526049051',
            #     'device_info': 'wupeiqi-min-program',
            #     'nonce_str': "".join([chr(random.randint(65, 90)) for _ in range(12)]),
            #     'sign_type': "MD5",
            #     'body': "保证金",
            #     'detail': '这是一个商品详细描述信息.',
            #     'attach': '微信小程序',
            #     'out_trade_no': uid,  # 商户系统内部订单号
            #     'total_fee': 1,  # 总金额
            #     'spbill_create_ip': '1.1.1.1',  # 终端IP（用户IP）
            #     'notify_url': "http://47.93.4.198:8012/pay/notify/",  # 支付成功之后，微信异步通知
            #     'trade_type': 'JSAPI',
            #     'openid': user_object.openid  # openid
            # }
            #
            # temp = "&".join(
            #     ["{0}={1}".format(k, data[k]) for k in sorted(data)] + ["{0}={1}".format("key", pay_key, ), ])
            # pre_sign = md5(temp).upper()
            # data['sign'] = pre_sign
            #
            # xml_string = "<xml>{0}</xml>".format("".join(["<{0}>{1}</{0}>".format(k, v) for k, v in data.items()]))
            # prepay = requests.post('https://api.mch.weixin.qq.com/pay/unifiedorder', data=xml_string.encode('utf-8'))
            # root = ET.XML(prepay.content.decode('utf-8'))
            # prepay_result = {child.tag: child.text for child in root}
            #
            # prepay_id = prepay_result['prepay_id']
            #
            # # ########### 2.2 创建支付签名 ###########
            # random_string = "".join([chr(random.randint(65, 90)) for _ in range(12)])
            # info = {
            #     'appId': "wx55cca0b94f723dc7",
            #     'timeStamp': str(int(time.time())),  # 时间戳从1970年1月1日00:00:00至今的秒数,即当前的时间
            #     'nonceStr': random_string,  # 随机字符串，长度为32个字符以下。
            #     'package': 'prepay_id={0}'.format(prepay_id),  # 统一下单接口返回的 prepay_id 参数值，提交格式如：prepay_id=*
            #     'signType': 'MD5',  # 签名类型，默认为MD5，支持HMAC-SHA256和MD5。注意此处需与统一下单的签名类型一致
            # }
            # temp = "&".join(
            #     ["{0}={1}".format(k, info[k]) for k in sorted(info)] + ["{0}={1}".format("key", pay_key, ), ])
            # sign = md5(temp).upper()
            # info['paySign'] = sign

        return deposit_object


class PayDetailModelSerializer(serializers.ModelSerializer):
    user_balance = serializers.IntegerField(source='user.balance')
    item = serializers.SerializerMethodField()
    coupon = serializers.SerializerMethodField()
    deposit = serializers.SerializerMethodField()
    pay_method = serializers.SerializerMethodField()

    class Meta:
        model = models.Order
        fields = "__all__"
        # exclude = ['auction', 'balance', 'uid', 'user']

    def get_item(self, obj):
        item = models.AuctionItem.objects.filter(id=obj.item.id, status=4).first()
        print(item)
        return model_to_dict(item, ['cover', 'title', 'uid'])

    def get_coupon(self, obj):
        coupon_user_object = models.UserCoupon.objects.filter(coupon__auction=obj.item.auction, user=self.context.user,
                                                              status=1)
        coupon_object_list = []
        for coupon_user in coupon_user_object:
            coupon_user_dict = {
                'id': coupon_user.id,
                'title': coupon_user.coupon.title,
                'money': coupon_user.coupon.money
            }
            coupon_object_list.append(coupon_user_dict)
        print(coupon_object_list)
        coupon_object_dict = {'count': coupon_user_object.count(), 'result': coupon_object_list}
        return coupon_object_dict

    def get_deposit(self, obj):
        user_object = self.context.user
        # 获取单品保证金
        deposit_object = models.DepositRecord.objects.filter(item=obj.item, status=2, user=user_object,
                                                             deposit_type=1).first()

        if not deposit_object:
            # 获取全场保证金
            deposit_object = models.DepositRecord.objects.filter(item__isnull=True, status=2, user=user_object,
                                                                 deposit_type=2, auction=obj.item.auction).first()
            print(deposit_object)
            # 获取订单查看全场保证金是否还拍到了其他单品
            order_object = models.Order.objects.filter(status=1, user=user_object,
                                                       item__auction=deposit_object.auction).exclude(
                id=obj.id)
            if not order_object:
                return model_to_dict(deposit_object, ['balance'])

            total = 0
            for row in order_object:
                total += row.item.deposit
            money = deposit_object.balance - total
            print(money, total)
            if money <= 0:
                return 0
            return {'balance': money}
        return model_to_dict(deposit_object, ['balance'])

    def get_pay_method(self, obj):
        balance = self.context.user.balance
        info = {
            'selected': 1,
            'choices': [
                {'id': 1, 'text': '微信支付'},
                {'id': 2, 'text': '余额（%s）' % balance},
            ]
        }
        return info
